
#pragma once

#if defined(__GNUC__) || defined(__MINGW__) || defined(__MINGW32__)
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Weffc++"
#endif

#include "libden/meta/can_recursive_iteration.h"

namespace Den{

    template<class Container, class ConcreteWay > 
    class IteratorBaseWrapper: public TWay<Container, ConcreteWay>::iterator
    {
        typedef IteratorBaseWrapper
            My;

        typedef typename 
            ::std::add_const<Container>::type
                cv;
        typedef typename 
            ::std::remove_const<Container>::type
                no_cv;

        friend 
            class IteratorWrapper<cv, ConcreteWay>;
        friend 
            class IteratorWrapper<no_cv, ConcreteWay>;
    public:
        typedef TWay<Container, ConcreteWay>
            way;
        typedef typename way::iterator
            iterator;
        typedef typename iterator::value_type
            value_type;

        enum { IS_WRAPPER = 1 };
        enum { IS_REVERSE = way::IS_REVERSE };

        enum { CAN_RECURSE =
            is_iterator_recursive<My, ConcreteWay>::value };

        enum { IS_CONST = ::std::is_const<Container>::value ||
            way::IS_CONST };

        typedef typename ::std::conditional<IS_CONST, cv, no_cv>::type
            contaiter_type;

        IteratorBaseWrapper()
            :iterator()
            ,mContainer(nullptr)
        {}
        IteratorBaseWrapper(cv& c, const iterator& cur )
            :iterator(cur)
            ,mContainer(&c)
        {}
        IteratorBaseWrapper(cv& c )
            :iterator( way::Beg(c) )
            ,mContainer(&c)
        {}
        IteratorBaseWrapper(no_cv& c, const iterator& cur )
            :iterator(cur)
            ,mContainer(&c)
        {}
        IteratorBaseWrapper(no_cv& c )
            :iterator( way::Beg(c) )
            ,mContainer(&c)
        {}

        IteratorBaseWrapper(const IteratorBaseWrapper& rhs)
            :iterator(rhs)
            ,mContainer(rhs.mContainer)
        {}

        template<class U>
        IteratorBaseWrapper(const IteratorBaseWrapper<U, ConcreteWay>& rhs)
            :iterator(rhs)
            ,mContainer(rhs.mContainer)
        {}

        IteratorBaseWrapper& operator=(no_cv& c)
        {
            static_cast<iterator&>(*this) = way::Beg(c);
            mContainer = &c;
            return *this;
        }

        IteratorBaseWrapper& operator=(cv& c)
        {
            static_cast<iterator&>(*this) = way::Beg(c);
            mContainer = &c;
            return *this;
        }

        template<class U>
        IteratorBaseWrapper& operator=(const IteratorBaseWrapper<U, ConcreteWay>& rhs)
        {
            static_cast<iterator&>(*this) = rhs;
            mContainer = rhs.mContainer;
            return *this;
        }

        operator bool()const  {  return !Empty(); }
        bool operator!()const {  return  Empty(); }

        bool Beg()const   
        {
            return mContainer && 
                static_cast<const iterator&>(*this)
                ==way::Beg(*mContainer);
        }
        bool End()const   
        {
            return  !mContainer || 
                static_cast<const iterator&>(*this)
                ==way::End(*mContainer);
        }
        bool Empty()const { return End(); }

        bool operator!=(const IteratorBaseWrapper& rhs)const{ return !operator==(rhs); }

        bool operator==(const IteratorBaseWrapper& rhs)const
        {
            const size_t empty_this  = Empty()?     1: 0;
            const size_t empty_other = rhs.Empty()? 1: 0;
            if(empty_this + empty_other == 2)
                return true;
            if(empty_this != empty_other)
                return false;
            const iterator& _rhs = static_cast<const iterator&>(rhs);
            const iterator& me   = static_cast<const iterator&>(*this);
            return _rhs==me;
        }
    private:
        contaiter_type* mContainer;
    };


#if 0
    template<class Container, class ConcreteWay > 
    class IteratorWrapper: public TWay<Container, ConcreteWay>::iterator
    {
        typedef typename ::std::add_const<Container>::type
            cv;
        typedef typename ::std::remove_const<Container>::type
            no_cv;

        friend 
            class IteratorWrapper<cv, ConcreteWay>;
        friend 
            class IteratorWrapper<no_cv, ConcreteWay>;
    public:
        typedef TWay<Container, ConcreteWay>
            way;
        typedef typename way::iterator
            iterator;
        typedef typename iterator::value_type
            value_type;

        enum { IS_WRAPPER = 1 };
        enum { IS_REVERSE = way::IS_REVERSE };
        
        enum { CAN_RECURSE =
            is_iterator_recursive<IteratorWrapper, ConcreteWay>::value };
        
        enum { IS_CONST = ::std::is_const<Container>::value ||
            way::IS_CONST };

        typedef typename ::std::conditional<IS_CONST, cv, no_cv>::type
            contaiter_type;

        IteratorWrapper()
            :iterator()
            ,mContainer(nullptr)
        {}
        IteratorWrapper(cv& c, const iterator& cur )
            :iterator(cur)
            ,mContainer(&c)
        {}
        IteratorWrapper(cv& c )
            :iterator( way::Beg(c) )
            ,mContainer(&c)
        {}
        IteratorWrapper(no_cv& c, const iterator& cur )
            :iterator(cur)
            ,mContainer(&c)
        {}
        IteratorWrapper(no_cv& c )
            :iterator( way::Beg(c) )
            ,mContainer(&c)
        {}

        IteratorWrapper(const IteratorWrapper& rhs)
            :iterator(rhs)
            ,mContainer(rhs.mContainer)
        {}

        template<class U>
        IteratorWrapper(const IteratorWrapper<U, ConcreteWay>& rhs)
            :iterator(rhs)
            ,mContainer(rhs.mContainer)
        {}

        IteratorWrapper& operator=(no_cv& c)
        {
            static_cast<iterator&>(*this) = way::Beg(c);
            mContainer = &c;
            return *this;
        }

        IteratorWrapper& operator=(cv& c)
        {
            static_cast<iterator&>(*this) = way::Beg(c);
            mContainer = &c;
            return *this;
        }

        template<class U>
        IteratorWrapper& operator=(const IteratorWrapper<U, ConcreteWay>& rhs)
        {
            static_cast<iterator&>(*this) = rhs;
            mContainer = rhs.mContainer;
            return *this;
        }

        operator bool()const  {  return !Empty(); }
        bool operator!()const {  return  Empty(); }

        bool Beg()const   
        {
            return mContainer && 
                static_cast<const iterator&>(*this)
                    ==way::Beg(*mContainer);
        }
        bool End()const   
        {
            return  !mContainer || 
                static_cast<const iterator&>(*this)
                    ==way::End(*mContainer);
        }
        bool Empty()const { return End(); }

        bool operator!=(const IteratorWrapper& rhs)const{ return !operator==(rhs); }

        bool operator==(const IteratorWrapper& rhs)const
        {
            const size_t empty_this  = Empty()?     1: 0;
            const size_t empty_other = rhs.Empty()? 1: 0;
            if(empty_this + empty_other == 2)
                return true;
            if(empty_this != empty_other)
                return false;
            const iterator& _rhs = static_cast<const iterator&>(rhs);
            const iterator& me   = static_cast<const iterator&>(*this);
            return _rhs==me;
        }

//         bool CanRecursive()const { return _CanRecursive<int>(); }
//         const IteratorWrapper& GetRecursiveIterator()const; { return _GetRecursiveIterator<int>(); }
//         IteratorWrapper GetRecursiveIterator();{ return _GetRecursiveIterator<int>(); }

    private:
#if 0
        #define IF_RECURSIVE      \
            typename ::std::enable_if< REVERSE, T>::type* = nullptr
        #define IF_NOT_RECURSIVE  \
            typename ::std::enable_if<!REVERSE, T>::type* = nullptr

        template<class T> 
            bool _CanRecursive(IF_NOT_RECURSIVE)const
                { return false; }

        template<class T>
        bool _CanRecursive(IF_RECURSIVE)const 
        {
            if(Empty())
                return false;

            const auto&  deep_iterator = GetRecursiveIterator();
            return deep_iterator? true: false;
            //auto sub = 
        }

        #undef IF_NOT_RECURSIVE
        #undef IF_RECURSIVE


        #define IF_REVERSE      \
            typename ::std::enable_if< REVERSE, T>::type* = nullptr
        #define IF_NOT_REVERSE  \
            typename ::std::enable_if<!REVERSE, T>::type* = nullptr

        template<class T> My& _GetRecursiveIterator(IF_NOT_REVERSE)
        {

        }
        template<class T> My& _GetRecursiveIterator(IF_REVERSE)
        {

        }

        #undef IF_NOT_REVERSE
        #undef IF_REVERSE
#endif
        

    protected:
        contaiter_type* mContainer;
    };

#endif

    template<class ConcreteWay,class Container> 
        IteratorWrapper<Container, ConcreteWay>
            MakeIterator(Container& c)
            {
                return IteratorWrapper<Container, ConcreteWay>(c);
            }

    template<class ConcreteWay,class Container, class Iter> 
        IteratorWrapper<Container, ConcreteWay>
            MakeIterator(Container& c, Iter&& i)
            {
                return IteratorWrapper<Container, ConcreteWay>(c, i);
            }

}//namespace Den


#if defined(__GNUC__) || defined(__MINGW__) || defined(__MINGW32__)
    #pragma GCC diagnostic pop
#endif
